CLI-52: Fix hang on interrupt during LLM processing#609
Conversation
Co-authored-by: cecli (openai/nvidia_nim/deepseek-ai/deepseek-v4-pro)
Co-authored-by: cecli (openai/code)
import pytest
from cecli.coders.base_coder import Coder
from tests.unit.test_run_parallel import test_run_parallel_first_completed, test_worker_interrupt_sets_both_flags_false
from tests.unit.test_interrupt_event import test_interrupt_event_cleared_in_run_parallel
from tests.unit.test_worker_interrupt import test_worker_interrupt_with_missing_input_running_attribute
@pytest.mark.asyncio
async def test_sub_agent_interrupt():
"""Test sub-agent interrupt."""
# Create a mock target_coder with the required attributes
target_coder = MagicMock(spec=BaseCoder)
target_coder.input_running = True
target_coder.output_running = True
target_coder.interrupt_event = MagicMock()
# Create worker instance
worker = CoderWorker(target_coder, MagicMock(), MagicMock())
# Call interrupt method - should not raise AttributeError
worker.interrupt()
# Assert output_running is still set to False
assert target_coder.output_running is False
```
**Explanation:**
1. **Import Necessary Modules:**
- `pytest`: For running unit tests.
- `cecli.coders.base_coder`: For the `BaseCoder` class, which represents a base coder for various tasks.
- `tests.unit.test_run_parallel`: Contains test functions for `test_run_parallel_first_completed` and `test_worker_interrupt_sets_both_flags_false`.
- `tests.unit.test_interrupt_event`: Contains test functions for `test_interrupt_event_cleared_in_run_parallel`.
- `tests.unit.test_worker_interrupt`: Contains test functions for `test_worker_interrupt_with_missing_input_running_attribute`
2. **Define Test Functions:**
- Each function is named with a descriptive name that indicates its purpose (e.g., `test_sub_agent_interrupt`).
3. **Create Mock Objects:**
- We create mock objects for the `BaseCoder` class and other relevant components to simulate real-world scenarios.
4. **Set Up Worker Instance:**
- We create a `CoderWorker` instance, passing in the mock `target_coder`.
5. **Call Interrupt Method:**
- We call the `interrupt()` method on the `worker` object. This simulates an interrupt event.
6. **Assert Results:**
- We assert that the output running flag is set to False after calling the interrupt method, ensuring the interrupt functionality works as expected.
**Key Points:**
* **Test Structure:** The test functions are structured in a way that allows you to easily test different aspects of the code's behavior.
* **Mock Objects:** Mock objects help isolate and control the behavior of specific parts of your code, making it easier to write tests for complex interactions.
**Running Tests:**
To run these tests:
1. Make sure you have pytest installed (`pip install pytest`).
2. Save the test code as a Python file (e.g., `test_interrupt_worker.py`).
3. Run the tests using the command `pytest test_interrupt_worker.py`.
Let me know if you'd like to explore more advanced testing techniques or have any other questions!
Co-authored-by: cecli (openai/code)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
|
You might be interested in: A lot of our deadlocks I think were disparate threads getting caught doing git commands through GitPython. The changes in this commit seem to allow multiple sub-agents to just rip on a task (I've personally tested up to 6 doing code base research). There may still be changes in here that mitigate other routes to the same locked behavior but these changes may be helpful in these investigations. The general thing implemented above is "get the system to gate keep each access to a singleton GitRepo instance" |
Nice, will take a gander. |
Bug:
ceclihangs in "Processing..." status after the user interrupts 2 or more times (Ctrl+C) during LLM processing.Root Cause: Asymmetric state reset in
worker.interrupt()- only setsoutput_running=Falsebut NOTinput_running=False.Fix: A layered approach was implemented:
worker.interrupt()asyncio.waittoFIRST_COMPLETEDinterrupt_eventis cleared in_run_parallel'sfinallyblock.Files Changed:
cecli/tui/worker.pycecli/coders/base_coder.pyReference: See
.cecli.plans.mdfor full details.